﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Web;
using Com.Toook.Common;
using Com.Toook.ParseHtml.Entity;
using Com.Toook.ParseHtml.Enum;

namespace Com.Toook.ParseHtml
{
    /// <summary>
    /// 根据xml配置文件创建Rule，Step解析对象
    /// </summary>
    public class CreateKindByXml
    {
        /// <summary>
        /// 网站的配置文件路径
        /// </summary>
        private string xmlPath = null;
        private Kind kind = new Kind();
        /// <summary>
        /// 根据一个网站的配置文件，解析出分类Kind的Rule/Step/Property等对象
        /// </summary>
        /// <param name="xmlPath">网站的配置文件路径</param>
        public CreateKindByXml(string xmlPath)
        {
            this.xmlPath = xmlPath;
        }    
        
        /// <summary>
        /// 获取一个分类对应的规则列表List&lt;Rule&gt;
        /// </summary>
        /// <param name="kindId">分类kind节点的id名称</param>       
        /// <returns></returns>
        public Kind GetKind(string kindId)
        {          
            //根据kindId获取xml节点
            string kindUrl;
            XmlNode kindNode = GetKindNodeFromXml(kindId, out kindUrl);
            //获取分类页面原始url
            kind.BaseUrl = kindUrl;
            kind.SiteKindId = kindId;
            int minLen = 1;
            if (null != kindNode.Attributes["minTitleLen"]) {
                minLen = int.Parse(kindNode.Attributes["minTitleLen"].Value);
            }            
            kind.MinTitleLength = minLen;//标题最小长度
            kind.SaveToTableName = kindNode.Attributes["insertTable"].Value;//保存结果的表名

            //获取分页规则
            XmlNode pageNode = kindNode.SelectSingleNode("pageRule");
            if (pageNode != null)
            {
                kind.PageRule = InitPageRule(pageNode);                
            }

            XmlNode initNode = kindNode.SelectSingleNode("initElements");
            kind.InitStep = ParseStep(initNode);//获取分类根元素解析步骤            

            XmlNodeList ruleList = kindNode.SelectNodes("rule");
            List<Rule> ruleListSteps = ParseRuleList(ruleList);
            kind.RuleList = ruleListSteps;

            return kind;
        }
        /// <summary>
        /// 如果分类有多个分页，解析出分页规则(如电影分类)
        /// </summary>
        /// <param name="pageNode"></param>
        private PageRule InitPageRule(XmlNode pageNode)
        {
            PageRule pageRule = new PageRule();
            try
            {
                pageRule.PageType = (PageType)System.Enum.Parse(typeof(PageType), pageNode.Attributes["type"].Value, true);
            }
            catch (Exception ex)
            {
                LogHelper.Log.Error("InitPageRule() 分页type错误。type=" + pageNode.Attributes["type"].Value, ex);
            }
            //1、按数字自动增长
            if (pageRule.PageType == PageType.Number)
            {
                XmlNodeList specialPage = pageNode.SelectNodes("specialPage");//开始的不规则页Url
                if (specialPage != null)
                {
                    pageRule.SpecialUrl = new List<string>(specialPage.Count);
                    foreach (XmlNode n in specialPage)
                    {
                        pageRule.SpecialUrl.Add(n.InnerText);
                    }
                }
                //规则页面
                pageRule.StartNum = int.Parse(pageNode.SelectSingleNode("startNum").InnerText);
                pageRule.MaxNum = int.Parse(pageNode.SelectSingleNode("maxNum").InnerText);
                pageRule.StartStr = pageNode.SelectSingleNode("startStr").InnerText;
                pageRule.EndStr = pageNode.SelectSingleNode("endStr").InnerText;                
            }
            else if (pageRule.PageType == PageType.FixedNumber) //2、固定宽度增长
            { 
            
            }
            else if (pageRule.PageType == PageType.NextPageRule)//3、根据Rule直接获取下一页Url
            {
                XmlNodeList stepNodes = pageNode.SelectNodes("step");
                XmlNodeList propNodes = pageNode.SelectNodes("property");
                if (stepNodes != null)
                {
                    foreach (XmlNode node in stepNodes)
                    {
                        Step step = ParseStep(node);
                        pageRule.NextPageRule.AddStep(step);
                    }
                }
                if (propNodes != null)
                {
                    foreach (XmlNode node in propNodes)
                    {
                        Property prop = ParseProperty(node);
                        pageRule.NextPageRule.AddProperty(prop);
                    }
                }
            }
            
            return pageRule;
        }        
       
        /// <summary>
        /// 获取配置文件中指定分类的XmlNode节点
        /// </summary>
        /// <returns></returns>
        private XmlNode GetKindNodeFromXml(string kindId, out string kindUrl)
        {
            XmlDocument docXml = new XmlDocument();
            docXml.Load(this.xmlPath);
            XmlElement root = docXml.DocumentElement;

            XmlNodeList kinds = root.SelectNodes("kind");
            
            foreach (XmlNode kind in kinds)
            {
                if (kindId == kind.Attributes["id"].Value)
                {
                    //return kind;

                    if (kind.Attributes["ref"] == null)//没有引用其他kind,自身定义了规则
                    {
                        kindUrl = kind.Attributes["url"].Value;
                        return kind;
                    }
                    else//引用其他kind的规则
                    {
                        string refId = kind.Attributes["ref"].Value;
                        kindUrl = kind.Attributes["url"].Value;
                        foreach (XmlNode k in kinds)
                        {
                            if (refId == k.Attributes["id"].Value)
                            {                                
                                return k;
                            }
                        }
                    }
                }
            }

            LogHelper.Log.Error("指定的kindId=" + kindId + "不存在。" + this.xmlPath);
            throw new Exception("指定的kindId=" + kindId + "不存在。" + this.xmlPath);
        }
       
        /// <summary>
        /// 将分类中的每个规则rule解析为对应的 ruleList
        /// </summary>
        /// <param name="rules">一个分类kind下的多个rule节点</param>
        /// <returns></returns>
        private List<Rule> ParseRuleList(XmlNodeList rules)
        {
            List<Rule> ruleList = new List<Rule>(rules.Count);//一个分类可能有多个解析规则

            foreach (XmlNode ruleNode in rules)
            {
                XmlNodeList steps = ruleNode.SelectNodes("step"); //获取step节点
                XmlNodeList propertys = ruleNode.SelectNodes("property");
                Rule rule = ParseRule(steps, propertys);
                //rule.EntityName = ruleNode.Attributes["entity"].Value;//设置实体名称
                ruleList.Add(rule);
            }

            return ruleList;
        }
        /// <summary>
        /// 解析出每个Step和propertys,添加到Rule
        /// </summary>
        /// <param name="steps"></param>
        /// <returns></returns>
        private Rule ParseRule(XmlNodeList steps, XmlNodeList propertys)
        {
            Rule rule = new Rule();//一个规则rule对应一个StepList  
            if (steps != null)
            {
                foreach (XmlNode stepNode in steps)
                {
                    Step step = ParseStep(stepNode);//将xml中的每个step节点解析为Step对象
                    rule.AddStep(step);
                }
            }
            foreach (XmlNode propertyNode in propertys) 
            {
                Property property = ParseProperty(propertyNode);//将xml中的每个property节点解析为Property对象
                rule.AddProperty(property);
            }

            return rule;
        }
        /// <summary>
        /// 解析实体的一个属性
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private Property ParseProperty(XmlNode node) {
            XmlNodeList steps = node.SelectNodes("step");
            XmlNode result = node.SelectSingleNode("result");

            Property property = new Property();
            property.PropertyName = node.Attributes["name"].Value;
            if (steps != null)//添加结果的解析步骤
            {
                foreach (XmlNode stepNode in steps)
                {
                    Step step = ParseStep(stepNode);//将xml中的每个step节点解析为Step对象
                    property.AddStep(step);//添加属性的step解析步骤
                }
            }
            //添加获取结果的规则
            property.Result = new XmlResult();
            string getBy = result.Attributes["getBy"].Value;
            try{
                property.Result.GetBy = (GetBy)System.Enum.Parse(typeof(GetBy), getBy, true);
            }
            catch (Exception ex)
            {
                LogHelper.Log.Error("ParseProperty() getBy=" + getBy + "不合法, 文件：" + this.xmlPath, ex);
            }    
            property.Result.Name = result.Attributes["name"].Value;
            XmlNode value = node.SelectSingleNode("value");
            property.Result.Value = value == null ? "" : value.InnerText;
            property.Result.ResultFilter = ParseFilter(result);
            return property;
        }        
        /// <summary>
        /// 将xml中的每个step节点解析为Step对象
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private Step ParseStep(XmlNode node)
        {
            Step step = new Step();
            string getBy = node.Attributes["getBy"].Value;
            step.Name = node.Attributes["name"].Value;
            XmlNode value = node.SelectSingleNode("value");
            step.Value = value == null ? "" : value.InnerText;

            step.FilterList = ParseFilter(node);

            try
            {
                step.GetBy = (GetBy)System.Enum.Parse(typeof(GetBy), getBy, true);
            }
            catch (Exception ex)
            {
                LogHelper.Log.Error("ParseStep() getBy=" + getBy + "不合法, 文件：" + this.xmlPath, ex);
            }           
        
            return step;
        }
        /// <summary>
        /// 解析过滤规则
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private List<Filter> ParseFilter(XmlNode node) {
            List<Filter> filterList = new List<Filter>();
            Filter filter = null;
            XmlNodeList filterNodes = node.SelectNodes("filter");
            if (filterNodes != null) {
                foreach (XmlNode f in filterNodes) { 
                    filter = new Filter();
                    //string filterType = f.Attributes["type"].Value;
                    //try
                    //{
                    //    filter.FilterType = (FilterType)System.Enum.Parse(typeof(FilterType), filterType, true);
                    //}
                    //catch (Exception ex)
                    //{
                    //    LogHelper.Log.Error("ParseFilter() FilterType=" + filterType + "不合法, 文件：" + this.xmlPath, ex);
                    //}
                    string getBy = f.Attributes["getBy"].Value;
                    filter.Name = f.Attributes["name"].Value;
                    XmlNode value = f.SelectSingleNode("value");
                    filter.Value = value == null ? "" : value.InnerText;

                    try
                    {
                        filter.GetBy = (GetBy)System.Enum.Parse(typeof(GetBy), getBy, true);
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Log.Error("ParseFilter() getBy=" + getBy + "不合法, 文件：" + this.xmlPath, ex);
                    }

                    filterList.Add(filter);
                }
            }

            return filterList;
        }
    }
}
